package com.macro.mall.portal.controller.commission;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.macro.mall.commission.domain.OrderPredicate;
import com.macro.mall.commission.entity.OrderPredicateEntity;
import com.macro.mall.commission.service.OrderPredicateService;
import com.macro.mall.commission.service.bo.PagedQueryOrderPredicateInput;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.common.api.input.PageConstants;
import com.macro.mall.common.api.util.BigDecimalUtils;
import com.macro.mall.common.api.util.LocalDateTimeUtils;
import com.macro.mall.common.api.util.Tuple;
import com.macro.mall.model.UmsMember;
import com.macro.mall.oms.entity.OrderItemEntity;
import com.macro.mall.oms.service.order.OrderItemService;
import com.macro.mall.portal.controller.BaseController;
import com.macro.mall.portal.domain.commission.OrderPredictVO;
import com.macro.mall.portal.dto.commission.ListOrderPredicateByTimeReqDto;
import com.macro.mall.portal.dto.commission.ListOrderPredicateByTimeResResult;
import com.macro.mall.ums.entity.MemberEntity;
import com.macro.mall.ums.service.account.MemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 订单佣金预估控制器
 *
 * @author xuyanjun
 * @date 2019-12-16
 */
@Api(tags = "OrderPredicateController", description = "订单佣金预估")
@Slf4j(topic = "OrderPredicateController")
@RestController
@RequestMapping("/orderPredicate")
public class OrderPredicateController extends BaseController {

    @Autowired
    private OrderPredicateService orderPredicateService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private OrderItemService orderItemService;

    /**
     * 根据时间查询订单预估佣金
     *
     * @return 根据时间查询订单预估佣金
     */
    @PreAuthorize("isAuthenticated()")
    @ApiOperation("根据时间查询订单预估佣金")
    @PostMapping("listByTime")
    public CommonResult<ListOrderPredicateByTimeResResult> listByTime(@RequestBody ListOrderPredicateByTimeReqDto reqDto) {
        final Tuple<LocalDateTime> localDateTimeTuple = obtainSearchTimeRange(reqDto.getTimeType());
        final UmsMember currentUser = getCurrentUser();

        final long amount = orderPredicateService.sumAmountByCreateTimeOfUser(currentUser.getId(), localDateTimeTuple.getItem1(), localDateTimeTuple.getItem2());

        PagedQueryOrderPredicateInput pagedQueryOrderPredicateInput = new PagedQueryOrderPredicateInput();
        pagedQueryOrderPredicateInput
                .setUserId(currentUser.getId())
                .setCreateBeginTime(localDateTimeTuple.getItem1())
                .setCreateEndTime(localDateTimeTuple.getItem2())
                .setSortField(PagedQueryOrderPredicateInput.CREATE_TIME_FIELD_NAME)
                .setSortDirection(PageConstants.DESC_SORT_DIRECTION)
                .setPageIndex(1)
                .setPageSize(200);

        Page<OrderPredicateEntity> page = orderPredicateService.pagedQuery(pagedQueryOrderPredicateInput);

        List<OrderPredicate> orderPredicates = orderPredicateService.entityToDomain(page);
         List<OrderPredictVO> orderPredictVOS = orderPredictToVO(orderPredicates);
        orderPredictVOS = orderPredictVOS.stream().sorted((x, y) ->
            x.getCreateTime().isAfter(y.getCreateTime()) ? -1 : 1
        ).collect(Collectors.toList());

        ListOrderPredicateByTimeResResult result = new ListOrderPredicateByTimeResResult();
        result.setTotal(BigDecimalUtils.fromFengToYuan((int) amount, 2))
                .setSettles(orderPredictVOS);

        return CommonResult.success(result);
    }

    /**
     * 获取搜索时间范围
     *
     * @param timeType 时间类型
     * @return 搜索时间范围
     */
    private Tuple<LocalDateTime> obtainSearchTimeRange(int timeType) {
        Tuple<LocalDateTime> tuple = new Tuple<>();

        if (ListOrderPredicateByTimeReqDto.PredictTimeTypeEnum.TODAY.getValue() == timeType) {
            LocalDateTime beginOfToday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
            tuple.setItem1(beginOfToday);
            tuple.setItem2(LocalDateTime.now());
        }

        if (ListOrderPredicateByTimeReqDto.PredictTimeTypeEnum.YESTERDAY.getValue() == timeType) {
            LocalDateTime beginOfYesterday = LocalDateTime.of(LocalDate.now().plusDays(-1), LocalTime.MIN);
            LocalDateTime endOfYesterday = LocalDateTime.of(LocalDate.now().plusDays(-1), LocalTime.MAX);

            tuple.setItem1(beginOfYesterday);
            tuple.setItem2(endOfYesterday);
        }

        if (ListOrderPredicateByTimeReqDto.PredictTimeTypeEnum.THIS_MONTH.getValue() == timeType) {
            tuple.setItem1(LocalDateTimeUtils.getFirstDateOfMonth());
            tuple.setItem2(LocalDateTimeUtils.getLastDateOfMonth());
        }

        if (ListOrderPredicateByTimeReqDto.PredictTimeTypeEnum.LAST_MONTH.getValue() == timeType) {
            LocalDateTime lastMonth = LocalDateTime.now().plusMonths(-1);
            tuple.setItem1(LocalDateTimeUtils.getFirstDateOfMonth(lastMonth));
            tuple.setItem2(LocalDateTimeUtils.getLastDateOfMonth(lastMonth));
        }

        return tuple;
    }

    private List<OrderPredictVO> orderPredictToVO(List<OrderPredicate> orderPredicates) {
        List<OrderPredictVO> orderPredictVOS = new ArrayList<>();
        final List<Long> userIds = orderPredicates.stream().map(OrderPredicate::getOrderUserId).distinct().collect(Collectors.toList());
        final List<Long> orderIds = orderPredicates.stream().map(OrderPredicate::getOrderId).distinct().collect(Collectors.toList());

        final List<MemberEntity> memberEntities = memberService.listByBatchIds(userIds);
        final List<OrderItemEntity> orderEntities = orderItemService.listByBatchOrderIds(orderIds);

        for (OrderPredicate orderPredicate : orderPredicates) {
            OrderPredictVO orderPredictVO = new OrderPredictVO();
            orderPredictVO.setSettled(true);
            BeanUtil.copyProperties(orderPredicate, orderPredictVO);
            memberEntities.stream().filter(x -> x.getId().equals(orderPredicate.getOrderUserId())).findFirst().ifPresent(x -> {
                orderPredictVO.setOrderUserHeadImgUrl(x.getIcon());
                orderPredictVO.setOrderUserName(x.getNickname());
            });
            orderEntities.stream().filter(x -> x.getOrderId().equals(orderPredicate.getOrderId())).findFirst().ifPresent(x -> {
                orderPredictVO.setProductImageUrl(x.getProductPic());
                orderPredictVO.setProductName(x.getProductName());
            });

            orderPredictVOS.add(orderPredictVO);
        }

        List<OrderPredictVO> result = new ArrayList<>();

        final Map<Long, List<OrderPredictVO>> groups = orderPredictVOS.stream().collect(Collectors.groupingBy(OrderPredictVO::getOrderId));
        groups.forEach((orderId, vos) -> {
            OrderPredictVO orderPredictVO = new OrderPredictVO();
            BeanUtil.copyProperties(vos.get(0), orderPredictVO);

            final BigDecimal amount = vos.stream().map(OrderPredictVO::getAmount).reduce(BigDecimalUtils::sum).get();
            orderPredictVO.setAmount(amount);

            result.add(orderPredictVO);
        });

        return result;
    }

    /**
     * 根据id获取订单佣金预估
     *
     * @param id id
     * @return 订单佣金预估
     */
    @ApiOperation("根据id获取订单佣金预估")
    @GetMapping("{id}")
    public CommonResult<OrderPredicate> getById(@PathVariable long id) {
        if (id <= 0) {
            throw new BusinessException("要获取的订单佣金预估Id不能为空。");
        }

        OrderPredicateEntity orderPredicateEntity = orderPredicateService.getById(id);
        if (orderPredicateEntity == null) {
            throw new BusinessException(String.format("要获取的订单佣金预估id:%s不存在。", id));
        }

        OrderPredicate orderPredicate = orderPredicateService.entityToDomain(orderPredicateEntity);
        return CommonResult.success(orderPredicate);
    }

    /**
     * 根据批量id获取订单佣金预估
     *
     * @param ids ids
     * @return 订单佣金预估
     */
    @ApiOperation("根据批量id获取订单佣金预估")
    @PostMapping("listByBatchIds")
    public CommonResult<List<OrderPredicate>> listByBatchIds(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("要获取的订单佣金预估Id集合不能为空。");
        }

        List<OrderPredicateEntity> orderPredicateEntities = orderPredicateService.listByBatchIds(ids);

        List<OrderPredicate> orderPredicates = orderPredicateService.entityToDomain(orderPredicateEntities);
        return CommonResult.success(orderPredicates);
    }

}

